package org.example.serialize;


import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;





import java.io.IOException;




/**
 * 脱敏序列化器
 *
 * StdSerializer：所有标准序列化程序所使用的基类，这个是编写自定义序列化程序所推荐使用的基类。
 * ContextualSerializer：是Jackson 提供的另一个序列化相关的接口，它的作用是通过字段已知的上下文信息定制JsonSerializer。
 * @author zhangxiaoxu15
 * @date 2022/2/8 11:10
 */
public class ObjectDesensitizeSerializer extends StdSerializer<Object> implements ContextualSerializer {
    private static final long serialVersionUID = -7868746622368564541L;
    private transient Desensitization<Object> desensitization;

    protected ObjectDesensitizeSerializer() {
        super(Object.class);
    }

    public Desensitization<Object> getDesensitization() {
        return desensitization;
    }

    public void setDesensitization(Desensitization<Object> desensitization) {
        this.desensitization = desensitization;
    }

    /**
     * 扫描到的进入序列化
     * createContextual可以获得字段的类型以及注解。当字段拥有自定义注解时，取出注解中的值创建定制的序列化方式，这样在serialize方法中便可以得到这个值了。
     * createContextual方法只会在第一次序列化字段时调用（因为字段的上下文信息在运行期不会改变），所以无需关心性能问题。
     * @param prov
     * @param property
     * @return
     */
    @Override
    public JsonSerializer<Object> createContextual(SerializerProvider prov, BeanProperty property) {
//获取属性注解
        Desensitize annotation = property.getAnnotation(Desensitize.class);
        return createContextual(annotation.desensitization());
    }

    @SuppressWarnings("unchecked")
    public JsonSerializer<Object> createContextual(Class<? extends Desensitization<?>> clazz) {
        ObjectDesensitizeSerializer serializer = new ObjectDesensitizeSerializer();
        if (clazz != DefaultDesensitization.class) {
            serializer.setDesensitization((Desensitization<Object>) DesensitizationFactory.getDesensitization(clazz));
        }
        return serializer;
    }

    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        Desensitization<Object> objectDesensitization = getDesensitization();
        if (objectDesensitization != null) {
            try {
                gen.writeObject(objectDesensitization.desensitize(value));
            } catch (Exception e) {
                gen.writeObject(value);
            }
        } else if (value instanceof String) {
            gen.writeString(Symbol.getSymbol(((String) value).length(), Symbol.STAR));
        } else {
            gen.writeObject(value);
        }
    }
}